﻿using System;
using System.Net;

using System.Collections.Generic;
using Topping.Core.Logic;
using TopMachine.Topping.Dto;
using Topping.Core.Logic;
using Topping.Core.Logic.Client;
using TopMachine.Desktop.Overall;

namespace Topping.Core.Proxy.Local.Client
{

    public class Session : ISession, IDisposable
    {

        public List<Room> Rooms { get; set; }
        public List<ConfigGameDto> Configurations { get; set; }
        public List<string> Pseudos { get; set; }

        public Room _currentRoom;

        public Room CurrentRoom
        {
            get { 
                return _currentRoom; 
            }
            set { 
                _currentRoom = value; 
            }
        }

        private bool authenticated = false;

        public bool Authenticated
        {
            get { return authenticated; }
            set { authenticated = value; }
        }

        private string pseudo = "";

        public string Pseudo
        {
            get { return pseudo; }
            set { pseudo = value; }
        }

        private string password = "";
        public string Password
        {
            get { return password; }
            set { password = value; }
        }


        public Session()
        {
            ;
        }

        public void CheckCurrentRoom(Room r)
        {
            if (CurrentRoom != null && CurrentRoom.RoomId == r.RoomId)
            {
                CurrentRoom = r;
            }
        }
        public void SetCompleteGame(int roomid)
        {
            FinalRoomDto finalroom;
            finalroom = MessageProxy.Proxy.getFinalRoom(roomid);

            MessageProxy.Proxy.DeleteCopy();
            // modif david
            if (MessageProxy.Proxy.GameState != null)
            {
                MessageProxy.Proxy.GameState.Dispose();
                MessageProxy.Proxy.GameState = null;
            }

            MessageProxy.Proxy.GameState = new GameState(CurrentRoom);
            MessageProxy.Proxy.GameState.GeneratedGame = finalroom.Game;
            MessageProxy.Proxy.GameState.FinalRoom = finalroom;

        }

        public void HandleMessageLocally(MessageDto message)
        {
            RoomDto r = null;
            Room rp = null;
            switch (message.MessageType)
            {
                case MessageType.Login:
                    if (!Pseudos.Contains(message.From))
                    {
                        Pseudos.Add(message.From);
                    }
                    break;
                case MessageType.Logoff:
                    Pseudos.Remove(message.From);
                    break;

                case MessageType.RoomCreate:
                    r = message.Room;
                    rp = Rooms.Find(p => p.RoomId == r.RoomId);
                    rp.SetDto(r);
                    //  rp.AddPlayer(message.From);
                    break;
                case MessageType.RoomEnter:
                    r = message.Room;
                    rp = Rooms.Find(p => p.RoomId == r.RoomId);
                    rp.SetDto(r);
                    rp.AddPlayer(message.From, false);
                    // Rooms.Add(rp);
                    break;
                case MessageType.RoomGameStart:
                    r = message.Room;
                    rp = Rooms.Find(p => p.RoomId == message.ToRoom);
                    rp.GameStartTime = DateTime.Now.AddSeconds(r.WaitingTime);
                    if (rp != null)
                    {
                        rp.GameStatus = RoomStatus.Started;
                    }

                    GeneratedGameDto ggd = MessageProxy.Proxy.GetGame();
                    MessageProxy.Proxy.GameState = MessageProxy.Proxy.SetGameState(r.Configuration);
                    MessageProxy.Proxy.GameState.GeneratedGame = ggd; ;

                    break;

                case MessageType.RoomLeave:
                    r = message.Room;
                    rp = Rooms.Find(p => p.RoomId == message.ToRoom);
                    rp.GameStartTime = DateTime.Now.AddSeconds(r.WaitingTime);
                    if (rp != null)
                    {
                        rp.RemovePlayer(message.From);
                    }
                    break;
                case MessageType.RoomStatusChange:
                    r = message.Room;
                    rp = Rooms.Find(p => p.RoomId == r.RoomId);
                    if (rp != null)
                    {
                        rp.GameStatus = r.GameStatus;
                        rp.TotalPlayers = r.TotalPlayers;
                        rp.GameStartTime = DateTime.Now.AddSeconds(r.WaitingTime);
                    }
                    break;
                case MessageType.GameSummaryUpdated:
                    PlayerSummaryDto pp = new ObjectSerializer<PlayerSummaryDto>().Deserialize(message.XmlObject);
                    MessageProxy.Proxy.GameState.AddSummary(pp);
                    break;
                case MessageType.GameSummaryRoundUpdated:
                    PlayedGameRoundDto psd = new ObjectSerializer<PlayedGameRoundDto>().Deserialize(message.XmlObject);
                    MessageProxy.Proxy.GameState.AddPlayedGameRoundDto(psd);
                    break;

                case MessageType.Private:

                    if (message.MessageModule == MessageModule.Game)
                    {
                        SerializableDictionary<string, List<PlayedGameRoundDto>> lst = new ObjectSerializer<SerializableDictionary<string, List<PlayedGameRoundDto>>>().Deserialize(message.XmlObject);
                        MessageProxy.Proxy.GameState.InitPlayedGameRoundDto(lst);
                    }
                    break;
            }

        }

        #region Message Handlers
        Dictionary<string, IMessageHandler> messageHandlers = new Dictionary<string, IMessageHandler>();
        Dictionary<string, IMessageHandler> tmpMessageHandlers = new Dictionary<string, IMessageHandler>();

        public void HandleMessage(MessageDto message)
        {
            HandleMessageLocally(message);

            lock (messageHandlers)
            {
                /* IMessageHandler[] mhs = new IMessageHandler[messageHandlers.Count];
                 messageHandlers.Values.CopyTo(mhs, 0); 

                 foreach (IMessageHandler mh in mhs)*/
                foreach (IMessageHandler mh in messageHandlers.Values)
                {
                    if (mh != null)
                    {
                        mh.HandleMessage(message);
                    }
                }
            }

            UpdateHandlers();

        }


        public void RemoveMessageHandler(string key)
        {
            lock (messageHandlers)
            {
                messageHandlers.Remove(key);
            }
        }


        private void UpdateHandlers()
        {
            lock (tmpMessageHandlers)
            {
                if (tmpMessageHandlers.Count > 0)
                {
                    foreach (string k in tmpMessageHandlers.Keys)
                    {
                        if (messageHandlers.ContainsKey(k))
                        {
                            messageHandlers[k] = null;
                            messageHandlers[k] = tmpMessageHandlers[k];
                        }
                        else
                        {
                            messageHandlers.Add(k, tmpMessageHandlers[k]);
                        }
                    }
                }

                tmpMessageHandlers.Clear();
            }
        }

        public void AddMessageHandler(string key, IMessageHandler h, bool update)
        {
            lock (tmpMessageHandlers)
            {
                if (tmpMessageHandlers.ContainsKey(key))
                {
                    tmpMessageHandlers.Remove(key);
                    tmpMessageHandlers.Add(key, h);
                }
                else
                {
                    tmpMessageHandlers.Add(key, h);
                }
            }

            if (update)
            {
                UpdateHandlers();
            }
        }

        #endregion



        #region IDisposable Members

        public void Dispose()
        {
            foreach (string h in messageHandlers.Keys)
            {
                MemoryCheck.AddError(messageHandlers[h].GetType().FullName + " Message Handler is not disposed");
            }

            tmpMessageHandlers.Clear();
            messageHandlers.Clear(); 

        }

        #endregion
    }

}
